package com.lucky.carcodepro.config.mybatis;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.lucky.carcodepro.common.SimpleSharding;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;

/**
 * SimpleShardingInterceptor
 * <p>
 * 描述：分表插件
 *
 * @author Annie
 * @version 2024/10/2 16:15
 */
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SimpleShardingInterceptor implements Interceptor
{

    @Override
    public Object intercept(Invocation invocation) throws Throwable
    {
        SimpleSharding.SimpleShardingBound sharding = SimpleSharding.get();
        if (ObjUtil.isNull(sharding))
        {
            return invocation.proceed();
        }
        StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        final BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        String sql = boundSql.getSql();
        // 替换表名为按月份分表
        String replaceSql = sql.replace(sharding.getTableName(), sharding.getShardingTableName());
        // 生成新的 SQL 继续执行
        BoundSql newBoundSql = new BoundSql(
                ms.getConfiguration(),
                replaceSql,
                boundSql.getParameterMappings(),
                boundSql.getParameterObject()
        );
        metaObject.setValue("delegate.boundSql.sql", newBoundSql.getSql());
        if (sharding.getNeedClear())
        {
            SimpleSharding.clear();
        }
        return invocation.proceed();
    }
}
